package com.ruoyi.ring.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.enums.TimeUnitEnums;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.ring.domain.*;
import com.ruoyi.ring.domain.dto.GeneralSecondDTO;
import com.ruoyi.ring.domain.dto.RingSleepDetailInfoDTO;
import com.ruoyi.ring.domain.vo.*;
import com.ruoyi.ring.mapper.RingEmotionalInfoMapper;
import com.ruoyi.ring.mapper.RingSleepDetailMapper;
import com.ruoyi.ring.mapper.RingStressChangeInfoMapper;
import com.ruoyi.ring.mapper.RingStressChangeMapper;
import com.ruoyi.ring.service.IPressureSecondService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class PressureSecondServiceImpl implements IPressureSecondService {
    @Resource
    private RingSleepDetailMapper sleepDetailMapper;
    @Resource
    private RingStressChangeMapper stressChangeMapper;
    @Resource
    private RingStressChangeInfoMapper stressChangeInfoMapper;
    @Resource
    private RingEmotionalInfoMapper emotionalInfoMapper;

    @Override
    public List<CalendarResultVO> queryCalendarList(GeneralSecondDTO secondDTO) {
        List<RingStressChangeInfo> stressChangeInfoList = stressChangeInfoMapper.selectRingStressChangeInfoList(Builder.of(RingStressChangeInfo::new).with(RingStressChangeInfo::setDeviceSn,secondDTO.getDeviceSn()).build());
        List<CalendarResultVO> resultVOS = new ArrayList<>();
        stressChangeInfoList.forEach(s ->{
            CalendarResultVO resultVO = new CalendarResultVO();
            resultVO.setDailyValue(s.getRecordTime());
            resultVOS.add(resultVO);
        });
        ZoneId zoneId = ZoneId.systemDefault();
        List<CalendarResultVO> list = resultVOS.stream()
                .collect(Collectors.toMap(
                        vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate(),
                        Function.identity(),
                        (existing, replacement) -> existing
                ))
                .values()
                .stream()
                // 使用Comparator.comparing指定按日期正序
                .sorted(Comparator.comparing(vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate()))
                .collect(Collectors.toList());
        return list;
    }
    @Override
    public GeneralAverageVO queryPressureAverage(GeneralSecondDTO secondDTO) {
        GeneralAverageVO averageVO = new GeneralAverageVO();
        //自动测量
        List<RingStressChangeInfo> stressChangeInfoList = stressChangeInfoMapper.queryRingStressChangeInfoList(secondDTO);
        List<Integer> pressureInfoList = new ArrayList<>();
        int average = 0;
        int maxValue;
        int minValue;
        List<GeneralAverageVO.ManualInfoVO> manualInfoVOList = new ArrayList<>();
        List<GeneralAverageVO.AutomaticInfoVO> automaticInfoVOList = new ArrayList<>();
        if("1".equals(secondDTO.getType())){ //睡眠信息
            RingSleepDetail sleepDetail = sleepDetailMapper.querySleepInfoDetail(Builder.of(RingSleepDetailInfoDTO::new).
                    with(RingSleepDetailInfoDTO::setDeviceSn, secondDTO.getDeviceSn()).
                    with(RingSleepDetailInfoDTO::setDailyValue, secondDTO.getRecordDate()).build());
            if(sleepDetail != null) {
                averageVO.setEndTime(DateUtils.convertDateTimeToHHMM(sleepDetail.getEndDate()));
            }
            if(stressChangeInfoList.size() > 0) {
                RingStressChangeInfo ringStressChangeInfo = stressChangeInfoList.get(0);
                String[] pressures = ringStressChangeInfo.getStressChangeList().replace("null", "0").replace("255", "0").split(",");//转成String数组
                pressureInfoList = Arrays.stream(pressures).map(Integer::parseInt).collect(Collectors.toList());
                average = Convert.toInt(pressureInfoList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
                int timeInterval = 24*60/pressureInfoList.size();
                for(int i = 0; i< pressureInfoList.size(); i++){
                    GeneralAverageVO.AutomaticInfoVO automaticInfoVO = new GeneralAverageVO.AutomaticInfoVO();
                    int bo = pressureInfoList.get(i);
                    // 计算当前时间（分钟）：初始0分钟，每次增加5分钟
                    int minutes = i * timeInterval;
                    // 格式化时间为HH:MM格式（补前导零）
                    automaticInfoVO.setCode(DateUtils.convertMinutesToHHMM(minutes));
                    automaticInfoVO.setValue(bo);
                    automaticInfoVOList.add(automaticInfoVO);
                }
            }
            //手动测量
            List<RingStressChange> stressChangeList = stressChangeMapper.queryStressChangeList(secondDTO);
            for (RingStressChange detail : stressChangeList){
                int value = detail.getStressChange();
                GeneralAverageVO.ManualInfoVO manualInfoVO = new GeneralAverageVO.ManualInfoVO();
                manualInfoVO.setCode(DateUtils.convertDateTimeToHHMM(detail.getEndTime()));
                manualInfoVO.setValue(Convert.toStr(value));
                manualInfoVOList.add(manualInfoVO);
                pressureInfoList.add(value);
            }
            maxValue = pressureInfoList.stream().filter(num -> num != 0).max(Integer::compare).orElse(0);
            minValue = pressureInfoList.stream().filter(num -> num != 0).min(Integer::compare).orElse(0);
            averageVO.setMaxValue(maxValue);
            averageVO.setMinValue(minValue);
            averageVO.setRecordDate(DateUtils.dateTimeChinese(secondDTO.getRecordDate()));
            averageVO.setWeekName(DateUtils.queryWeekday(secondDTO.getRecordDate()));
        }else {
            List<Integer> total = new ArrayList<>();
            for (RingStressChangeInfo ringStressChangeInfo : stressChangeInfoList){
                GeneralAverageVO.AutomaticInfoVO automaticInfoVO = new GeneralAverageVO.AutomaticInfoVO();
                String[] strs = ringStressChangeInfo.getStressChangeList().replace("null", "0").replace("255", "0").split(",");//转成String数组
                List<Integer> stressChangeInfos = Arrays.stream(strs).map(Integer::parseInt).collect(Collectors.toList());
                total.addAll(stressChangeInfos);
                if("2".equals(secondDTO.getType())) automaticInfoVO.setCode(DateUtils.convertDateToMMdd(ringStressChangeInfo.getRecordTime()));
                if("3".equals(secondDTO.getType())) automaticInfoVO.setCode(DateUtils.queryMonthday(ringStressChangeInfo.getRecordTime()));
                maxValue = stressChangeInfos.stream().filter(num -> num != 0).max(Integer::compare).orElse(0);
                minValue = stressChangeInfos.stream().filter(num -> num != 0).min(Integer::compare).orElse(0);
                automaticInfoVO.setMaxValue(maxValue);
                automaticInfoVO.setMinValue(minValue);
                automaticInfoVOList.add(automaticInfoVO);
                //情绪
                List<RingEmotionalInfo> emotionalInfos= emotionalInfoMapper.selectRingEmotionalInfoList(Builder.of(RingEmotionalInfo::new).
                        with(RingEmotionalInfo::setDeviceSn, secondDTO.getDeviceSn()).
                        with(RingEmotionalInfo::setDailyValue, secondDTO.getRecordDate()).
                        with(RingEmotionalInfo::setUserId, SecurityUtils.getUserId()).build());
                for (RingEmotionalInfo detail : emotionalInfos){
                    GeneralAverageVO.ManualInfoVO manualInfoVO = new GeneralAverageVO.ManualInfoVO();
                    manualInfoVO.setCode(detail.getRecordTime());
                    manualInfoVO.setValue(detail.getEmotionalState());
                    manualInfoVOList.add(manualInfoVO);
                }
            }
            average = Convert.toInt(total.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
            Date dateStart = TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType()) ? DateUtils.getWeekStart(secondDTO.getRecordDate(), ZoneId.systemDefault()) : DateUtils.getMonthStart(secondDTO.getRecordDate(), ZoneId.systemDefault());
            Date dateEnd = TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType()) ? DateUtils.getWeekEnd(secondDTO.getRecordDate(), ZoneId.systemDefault()) : DateUtils.getMonthEnd(secondDTO.getRecordDate(), ZoneId.systemDefault());
            averageVO.setDateStart(DateUtils.dateTimeChinese(dateStart) + "，" + DateUtils.queryWeekday(dateStart));
            averageVO.setDateEnd(DateUtils.dateTimeChinese(dateEnd) + "，" + DateUtils.queryWeekday(dateEnd));
        }
        averageVO.setAverage(average);
        averageVO.setManualInfoVOS(manualInfoVOList);
        averageVO.setAutomaticInfoVOS(automaticInfoVOList);
        return averageVO;
    }

    @Override
    public List<PressureRateVO> queryPressureMonitor(GeneralSecondDTO secondDTO) {
        List<PressureRateVO> rateVOS = new ArrayList<>();
        //自动测量
        List<RingStressChangeInfo> stressChangeInfoList = stressChangeInfoMapper.queryRingStressChangeInfoList(secondDTO).stream().sorted(Comparator.comparingLong(RingStressChangeInfo::getId)).collect(Collectors.toList());
        if("1".equals(secondDTO.getType())){
            RingStressChangeInfo stressChangeInfo = stressChangeInfoList.get(0);
            String strValue = stressChangeInfo.getStressChangeList().replace("null", "0").replace("255","0");
            // 遍历所有数据点
            List<Integer> valueList = Arrays.stream(strValue.split(","))
                    .map(String::trim) // 去除每个元素前后的空格
                    .map(Integer::parseInt) // 转换为整数
                    .collect(Collectors.toList());
            rateVOS = analyzeValueList(valueList);
        }else {
            List<Integer> list = new ArrayList<>();
            for (RingStressChangeInfo stressChangeInfo : stressChangeInfoList){
                String strValue = stressChangeInfo.getStressChangeList().replace("null", "0").replace("255","0");
                // 遍历所有数据点
                List<Integer> valueList = Arrays.stream(strValue.split(","))
                        .map(String::trim) // 去除每个元素前后的空格
                        .map(Integer::parseInt) // 转换为整数
                        .collect(Collectors.toList());
                list.addAll(valueList);
            }
            rateVOS = analyzeValueList(list);
        }
        return rateVOS;
    }

    @Override
    public  List<GeneralInfoListVO> queryPressureInfoList(GeneralSecondDTO secondDTO) {
        List<GeneralInfoListVO> list = new ArrayList<>();
        List<GeneralGroupVO> groupVOList = stressChangeMapper.queryStressChangeDetailList(secondDTO);
        for (GeneralGroupVO group : groupVOList) {
            GeneralInfoListVO infoListVO = new GeneralInfoListVO();
            infoListVO.setDateStart(group.getDateStart());
            infoListVO.setDateEnd(group.getDateEnd());
            infoListVO.setDailyValue(group.getDailyValue());
            infoListVO.setWeekName(group.getWeekName());
            String groupData = group.getGroupData(); // 包含多条记录的JSON数组
            // 解析JSON数组为具体的实体类（假设有子实体类 BloodOxygenDetail）
            if(groupData != null){
                JSONArray jsonArray = JSONArray.parseArray(groupData);
                List<JsonObjectVO> jsonObjectVOList = jsonArray.toJavaList(JsonObjectVO.class);
//                infoListVO.setJsonObjectVOList(jsonObjectVOList.stream().sorted().collect(Collectors.toList()));
                jsonObjectVOList = jsonObjectVOList.stream().sorted(Comparator.comparingLong(JsonObjectVO::getId).reversed()).collect(Collectors.toList());
                infoListVO.setJsonObjectVOList(jsonObjectVOList);
            }
            list.add(infoListVO);
        }
        return list;
    }

    @Override
    public GeneralDetailListVO queryPressureDetail(Long id) {
        RingStressChange stressChange = stressChangeMapper.selectRingStressChangeById(id);
        GeneralDetailListVO bloodOxygenDetailVO = Convert.convert(GeneralDetailListVO.class,stressChange);
        bloodOxygenDetailVO.setGeneralValue(stressChange.getStressChange());
        bloodOxygenDetailVO.setWeek(DateUtils.queryWeekday(stressChange.getDailyValue()));
        bloodOxygenDetailVO.setEndHm(DateUtils.convertDateTimeToHHMM(stressChange.getEndTime()));
        return bloodOxygenDetailVO;
    }

    @Override
    public List<Integer> queryPressureSevenInfo(GeneralSecondDTO secondDTO) {
        List<RingStressChange> detailList = stressChangeMapper.queryStressChangeSevenInfo(secondDTO.getDeviceSn(),new Date());
        List<Integer> stressChanges = detailList.stream().map(RingStressChange::getStressChange).collect(Collectors.toList());
        return stressChanges;
    }


    /**
     * 组和压力比例
     */
    public List<PressureRateVO> analyzeValueList(List<Integer> valueList) {
        List<PressureRateVO> list = new ArrayList<>();
        PressureRateVO rateVO ;
        // 过滤掉0值并计算总和
        int totalSum = valueList.stream()
                .filter(v -> v != 0)
                .mapToInt(Integer::intValue)
                .sum();

        // 按范围分组统计总和
        int less30Sum = valueList.stream()
                .filter(v -> v < 30 && v != 0)
                .mapToInt(Integer::intValue)
                .sum();

        int range30To49Sum = valueList.stream()
                .filter(v -> v >= 30 && v <= 49)
                .mapToInt(Integer::intValue)
                .sum();

        int range50To79Sum = valueList.stream()
                .filter(v -> v >= 50 && v <= 79)
                .mapToInt(Integer::intValue)
                .sum();

        int moreOrEqual80Sum = valueList.stream()
                .filter(v -> v >= 80)
                .mapToInt(Integer::intValue)
                .sum();

        // 计算每个范围的初始百分比（使用整数运算避免精度问题）
        int p1 = calculatePercentage(less30Sum, totalSum);
        int p2 = calculatePercentage(range30To49Sum, totalSum);
        int p3 = calculatePercentage(range50To79Sum, totalSum);
        int p4 = calculatePercentage(moreOrEqual80Sum, totalSum);
        // 计算当前总和并调整最后一个百分比确保总和为100
        int currentTotal = p1 + p2 + p3 + p4;
        if (currentTotal != 100) {
            p1 += (100 - currentTotal);
        }
        rateVO = new PressureRateVO();
        rateVO.setInfo("优秀");
        rateVO.setValue(p1);
        list.add(rateVO);

        rateVO = new PressureRateVO();
        rateVO.setInfo("良好");
        rateVO.setValue(p2);
        list.add(rateVO);

        rateVO = new PressureRateVO();
        rateVO.setInfo("合格");
        rateVO.setValue(p3);
        list.add(rateVO);

        rateVO = new PressureRateVO();
        rateVO.setInfo("不足");
        rateVO.setValue(p4);
        list.add(rateVO);
        return list;
    }

    /**
     * 计算百分比（使用四舍五入确保整数结果）
     */
    private static int calculatePercentage(int part, int total) {
        if (total == 0) return 0;
        // 使用整数运算实现四舍五入，避免浮点数精度问题
        return (part * 100 + total / 2) / total;
    }

}
